import Vue from 'vue'
import Router from 'vue-router'
import mutations from '../store/mutations'

const md5Base64 = require('md5-base64')

Vue.use(Router)

Vue.mixin({
    // 全局增加字面量路由跳转
    methods: {
        $routerTo(path, params){
            this.$router.push({name: path, query: params})
        }
    },
});

let components = {}
const getComponents = function (routes) {
    routes.forEach(item => {
        if (item.component && item.name) {
            components[item.name] = item.component
        }
        if (item.children) {
            getComponents(item.children)
        }
    })
}

const encode = function ({name, query, meta, path}) {
    const isMultiPage = typeof meta.isMultiPage === 'boolean' ? meta.isMultiPage : true
    if (isMultiPage) {
        let q = Object.assign({}, query)
        if (q['_']) {
            delete q['_']
        }
        if (q.noRefresh) {
            delete q.noRefresh
        }
        return md5Base64(name + JSON.stringify(q))
    } else {
        return md5Base64(path)
    }
}

const getRoutes = function (routes) {
    routes.forEach(item => {
        if (item.component && item.name) {
            item.props = true
            item.meta = Object.assign({}, item.component.config || {}, item.meta || {})
            item.component.name = item.component.name || item.name
        }

        if (item.children) {
            getRoutes(item.children)
        }
    })
    return routes
}

const getComponent = function (name) {
    return components[name]
}

export default function (routes) {
    getComponents(routes)
    getRoutes(routes)

    const router = new Router({
        routes
    })

    router.beforeEach((to, from, next) => {
        if (to.name && to.meta.isModal) {
            // 需要注意 vuex只监听已经存在的属性，应全部提前定义好
            /*
            Mutation 需遵守 Vue 的响应规则
            既然 Vuex 的 store 中的状态是响应式的，那么当我们变更状态时，监视状态的 Vue 组件也会自动更新。这也意味着 Vuex 中的 mutation 也需要与使用 Vue 一样遵守一些注意事项：

            最好提前在你的 store 中初始化好所有所需属性。

            当需要在对象上添加新属性时，你应该

            使用 Vue.set(obj, 'newProp', 123), 或者

            以新对象替换老对象。例如，利用 stage-3 的对象展开运算符我们可以这样写：

            state.obj = { ...state.obj, newProp: 123 }

            https://vuex.vuejs.org/zh-cn/mutations.html
             */
            let component = getComponent(to.name)
            if (!to.meta.title) {
                throw new Error(`在modal模式下，请在 Component (${to.name}) config中设置title`)
            }
            router.app.$store.commit(mutations.MODAL_PUSH_PAGE, {
                component: component,
                state: to,
                ...to.meta,
                visible: true
            })
            // next(false) // 判断语句未生效，打开modal还会引起页面报错，暂时注释，del by weizq
        } else {
            const keepAlive = !!to.query.noRefresh || !!to.query['_'] // noRefresh属性控制router.push是否重新渲染页面,add by weizq
            if (!to.query['_']) {
                to.query['_'] = encode(to)
            }
            Vue.nextTick(function () {
                try {
                    if (to.name !== 'login' && !!to.name && router.app.$store.state.tabView.isEnabled) {
                        const pages = router.app.$store.state.tabView.pages
                        const idx = pages.findIndex(item => item.query['_'] === to.query['_'])
                        if (idx > -1) {
                            router.app.$store.commit(mutations.TAB_VIEW_PUSH, {
                                ...pages[idx],
                                keepAlive
                            })
                        } else {
                            router.app.$store.commit(mutations.TAB_VIEW_PUSH, {
                                fullPath: to.fullPath,
                                hash: to.hash,
                                meta: to.meta,
                                name: to.name,
                                params: to.params,
                                path: to.path,
                                query: to.query,
                                keepAlive,
                                title: null
                            })
                        }
                    }
                } catch (e) {
                }
            })
            next()
        }
    })
    return router
}
